﻿//#define Debug

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using DD.DDTelnetLib;
using DD.DDMudLibrary;

namespace DD.DDMudClient
{
    public partial class DDMudClient : Form
    {
        private DDTelnetClient Client = new DDTelnetClient();

        private int CurrentLine = 0;
        private int MaxLine = 1024;

        private Thread ThreadLoopShowMsg;
        private bool StopShowMsg = false;
        private bool ShowMsgEnd = true;

        private List<NamedTimer> TimerList = new List<NamedTimer>();
        private DDMudCommandProcessor CommandProcessor;

        public DDMudClient()
        {
            InitializeComponent();
        }

        private void ShowReadMsg()
        {
            char NextChar = '\0';

            while (!StopShowMsg)
            {
                if (Client.NextCharAvailable)
                {
                    if (Client.GetNextChar(out NextChar))
                    {
                        ShowChar(NextChar);
                    }
                    else
                    {
                    }
                }
                Thread.Sleep(1);
            }
            ShowMsgEnd = true;
        }

        private delegate void ShowCharCallback(char NextChar);

        private void ShowChar(char NextChar)
        {
            if (this.richTextBoxMessage.InvokeRequired)
            {
                ShowCharCallback D = new ShowCharCallback(ShowChar);
                this.Invoke(D, new object[] { NextChar });
            }
            else
            {
                if(Client.ANSIStat.Change)
                {
                    if (Client.ANSIStat.Bright)
                    {
                        switch (Client.ANSIStat.TextColor)
                        {
                            case 0:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(128, 128, 128);
                                break;
                            case 1:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(255, 0, 0);
                                break;
                            case 2:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(0, 255, 0);
                                break;
                            case 3:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(255, 255, 0);
                                break;
                            case 4:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(0, 0, 255);
                                break;
                            case 5:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(255, 0, 255);
                                break;
                            case 6:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(0, 255, 255);
                                break;
                            case 7:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(255, 255, 255);
                                break;
                        }
                    }
                    else
                    {
                        switch (Client.ANSIStat.TextColor)
                        {
                            case 0:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(0, 0 ,0);
                                break;
                            case 1:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(128, 0, 0);
                                break;
                            case 2:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(0, 128, 0);
                                break;
                            case 3:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(128, 128, 0);
                                break;
                            case 4:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(0, 0, 128);
                                break;
                            case 5:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(128, 0, 128);
                                break;
                            case 6:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(0, 128, 128);
                                break;
                            case 7:
                                this.richTextBoxMessage.SelectionColor = Color.FromArgb(192, 192, 192);
                                break;
                        }
                    }
                    switch (Client.ANSIStat.BackgroundColor)
                    {
                        case 0:
                            this.richTextBoxMessage.SelectionBackColor = Color.FromArgb(0, 0, 0);
                            break;
                        case 1:
                            this.richTextBoxMessage.SelectionBackColor = Color.FromArgb(128, 0, 0);
                            break;
                        case 2:
                            this.richTextBoxMessage.SelectionBackColor = Color.FromArgb(0, 128, 0);
                            break;
                        case 3:
                            this.richTextBoxMessage.SelectionBackColor = Color.FromArgb(128, 128, 0);
                            break;
                        case 4:
                            this.richTextBoxMessage.SelectionBackColor = Color.FromArgb(0, 0, 128);
                            break;
                        case 5:
                            this.richTextBoxMessage.SelectionBackColor = Color.FromArgb(128, 0, 128);
                            break;
                        case 6:
                            this.richTextBoxMessage.SelectionBackColor = Color.FromArgb(0, 128, 128);
                            break;
                        case 7:
                            this.richTextBoxMessage.SelectionBackColor = Color.FromArgb(192, 192, 192);
                            break;
                    }

                    Client.ANSIStat.Change = false;
                }
                this.richTextBoxMessage.AppendText(NextChar.ToString());
                this.richTextBoxMessage.SelectionStart = this.richTextBoxMessage.Text.Length;

                if (NextChar == '\n')
                {
                    CurrentLine++;
                    while (CurrentLine > MaxLine)
                    {
                        richTextBoxMessage.Text = richTextBoxMessage.Text.Substring(richTextBoxMessage.Text.IndexOf('\n') + 1);
                        CurrentLine--;
                    }

                    this.richTextBoxMessage.ScrollToCaret();
                }
            }
        }

        public void ShowClientMsg(string Str)
        {
            ShowClientMsg(Str, Color.White, Color.Black);
        }

        private delegate void ShowClientMsgCallback(string Str, Color TextColor, Color BackColor);

        private void ShowClientMsg(string Str, Color TextColor, Color BackColor)
        {
            if (this.richTextBoxMessage.InvokeRequired)
            {
                ShowClientMsgCallback D = new ShowClientMsgCallback(ShowClientMsg);
                this.Invoke(D, new object[] { Str, TextColor, BackColor });
            }
            else
            {
                if (Str == "")
                {
                    this.richTextBoxMessage.Text = "";
                }
                else
                {
                    Color SavedColor = this.richTextBoxMessage.SelectionColor;
                    Color SavedBackColor = this.richTextBoxMessage.SelectionBackColor;

                    this.richTextBoxMessage.SelectionColor = TextColor;
                    this.richTextBoxMessage.SelectionBackColor = BackColor;
                    this.richTextBoxMessage.AppendText(Str);
                    this.richTextBoxMessage.ScrollToCaret();

                    this.richTextBoxMessage.SelectionColor = SavedColor;
                    this.richTextBoxMessage.SelectionBackColor = SavedBackColor;

                    int i = 0;
                    while (i != -1)
                    {
                        if ((i = Str.IndexOf('\n', i)) != -1)
                        {
                            CurrentLine++;
                            i++;
                        }
                    }
                    while (CurrentLine > MaxLine)
                    {
                        richTextBoxMessage.Text = richTextBoxMessage.Text.Substring(richTextBoxMessage.Text.IndexOf('\n') + 1);
                        CurrentLine--;
                    }
                }
            }
        }

        private void DDTelnetLibTester_FormClosing(object sender, FormClosingEventArgs e)
        {
            StopShowMsg = true;
            Client.Disconnect();
//            if (e.CloseReason == CloseReason.UserClosing)
//            {
//                e.Cancel = true;
//            }
        }

        private void DDTelnetLibTester_FormClosed(object sender, FormClosedEventArgs e)
        {
            Environment.Exit(Environment.ExitCode);
        }

        private void DDTelnetLibTester_Load(object sender, EventArgs e)
        {
            CommandProcessor = new DDMudCommandProcessor(SetTimer, ShowClientMsg);
        }

        private void DDTelnetLibTester_MouseClick(object sender, MouseEventArgs e)
        {
            
        }

        private void textBoxCommandLine_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (Client.IsConnecting)
            {
                if (e.KeyChar == '\r')
                {
                    string RealCommand = CommandProcessor.ProcessOneCommand(textBoxCommandLine.Text);
                    if (RealCommand != "")
                    {
                        ShowClientMsg(textBoxCommandLine.Text + "\n");
                    }
                    if (!Client.SendString(RealCommand) ||
                        !Client.IsConnecting)
                    {
                        Client.Disconnect();
                        ShowClientMsg("已斷線！\n");
                    }

                    textBoxCommandLine.Text = "";
                }
            }
            else
            {
                if (e.KeyChar == '\r')
                {
                    string TempAddr = textBoxCommandLine.Text.Trim();

                    if (TempAddr == "")
                    {
                        TempAddr = "roc.csie.org:5555";
                    }
                    
                    ShowClientMsg("嘗試連線到" + TempAddr + " ……\r\n");

                    if (!Client.Connect(TempAddr.Substring(0, TempAddr.IndexOf(':')),
                        Convert.ToInt32(TempAddr.Substring(TempAddr.IndexOf(':') + 1))))
                    {
                        ShowClientMsg("連線失敗！\n");
                    }
                    else
                    {
                        if (ShowMsgEnd == true)
                        {
                            ThreadLoopShowMsg = null;
                            ShowMsgEnd = false;
                        }

                        if (ThreadLoopShowMsg == null)
                        {
                            ThreadLoopShowMsg = new Thread(ShowReadMsg);
                            ThreadLoopShowMsg.IsBackground = true;
                            ShowMsgEnd = false;
                            StopShowMsg = false;
                            ThreadLoopShowMsg.Start();
                        }
                    }

                    textBoxCommandLine.Text = "";
                }
            }
        }

        private void DDTelnetLibTester_Resize(object sender, EventArgs e)
        {
            richTextBoxMessage.Width = this.Width - 40;
            richTextBoxMessage.Height = this.Height - 93;
            textBoxCommandLine.Width = this.Width - 40;
            textBoxCommandLine.Top = this.Height - 75;
        }
        
        private void textBoxCommandLine_Enter(object sender, EventArgs e)
        {
            //textBoxCommandLine.SelectAll();
        }

        private class NamedTimer : System.Windows.Forms.Timer
        {
            public string Name = "";

            public NamedTimer(string InputName)
                : base()
            {
                Name = InputName;
            }
        }

        public void SetTimer(int Ms)
        {
            NamedTimer newTimer = new NamedTimer("Timer" + TimerList.Count.ToString());

            newTimer.Interval = Ms;
            newTimer.Tick += new EventHandler(TimerEventHandler);
            newTimer.Start();

            TimerList.Add(newTimer);
        }

        private void TimerEventHandler(Object myObject, EventArgs myEventArgs)
        {
            Client.InsertMessageLine(((NamedTimer)myObject).Name + " ticks!");
        }
    }
}
